package org.lanyu.springainovel.common.service;

import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 文件系统MCP服务集成�? * 提供文件系统操作的高级接口，封装MCP客户端调�? */
@Slf4j
@Service
public class FileSystemMcpService {
    
    /**
     * 文件系统MCP客户端缓存，key为允许的目录路径，value为McpSyncClient
     */
    private final Map<String, McpSyncClient> fsClients = new ConcurrentHashMap<>();
    
    /**
     * 默认允许的目�?     */
    private String defaultAllowedDirectory = System.getProperty("user.dir");
    
    /**
     * 设置默认允许的目�?     */
    public void setDefaultAllowedDirectory(String directory) {
        this.defaultAllowedDirectory = directory;
        log.info("设置文件系统MCP服务默认允许目录: {}", directory);
    }
    
    /**
     * 获取或创建文件系统MCP客户�?     */
    private McpSyncClient getOrCreateFileSystemClient(String allowedDirectory) {
        // 使用默认目录如果未指�?
        String dir = allowedDirectory != null ? allowedDirectory : defaultAllowedDirectory;
        
        // 检查目录是否存�?
        File directory = new File(dir);
        if (!directory.exists() || !directory.isDirectory()) {
            log.error("指定的目录不存在或不是目�? {}", dir);
            throw new IllegalArgumentException("指定的目录不存在或不是目�? " + dir);
        }
        
        // 检查是否已有缓存的客户�?
        if (fsClients.containsKey(dir)) {
            return fsClients.get(dir);
        }
        
        try {
            // 创建服务器参�?
            ServerParameters serverParams = ServerParameters.builder("npx")
                .args("-y", "@modelcontextprotocol/server-filesystem", dir)
                .build();
            
            // 创建stdio传输
            StdioClientTransport transport = new StdioClientTransport(serverParams);
            
            // 创建MCP客户�?
            McpSyncClient client = McpClient.sync(transport)
                .clientInfo(new McpSchema.Implementation("novel-serve", "1.0.0"))
                .build();
            
            // 初始化客户端
            client.initialize();
            
            // 缓存客户�?
            fsClients.put(dir, client);
            
            log.info("成功创建文件系统MCP客户端，允许目录: {}", dir);
            return client;
            
        } catch (Exception e) {
            log.error("创建文件系统MCP客户端失败，目录: {}", dir, e);
            throw new RuntimeException("创建文件系统MCP客户端失�? " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取文件内容
     */
    public String readFile(String filePath, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of("path", filePath);
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("read_file", arguments)
            );
            
            // 提取内容
            if (result.content() != null && !result.content().isEmpty()) {
                return extractTextContent(result.content());
            }
            
            return null;
            
        } catch (Exception e) {
            log.error("读取文件失败，路�? {}", filePath, e);
            throw new RuntimeException("读取文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 写入文件内容
     */
    public boolean writeFile(String filePath, String content, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of(
                "path", filePath,
                "content", content
            );
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("write_file", arguments)
            );
            
            // 检查结�?
            if (result.content() != null && !result.content().isEmpty()) {
                String resultText = extractTextContent(result.content());
                log.info("写入文件结果: {}", resultText);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            log.error("写入文件失败，路�? {}", filePath, e);
            throw new RuntimeException("写入文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 列出目录内容
     */
    public List<String> listDirectory(String dirPath, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of("path", dirPath);
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("list_directory", arguments)
            );
            
            // 提取内容
            if (result.content() != null && !result.content().isEmpty()) {
                String content = extractTextContent(result.content());
                // 按行分割并返回列�?
                return Arrays.asList(content.split("\n"));
            }
            
            return Collections.emptyList();
            
        } catch (Exception e) {
            log.error("列出目录失败，路�? {}", dirPath, e);
            throw new RuntimeException("列出目录失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建目录
     */
    public boolean createDirectory(String dirPath, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of("path", dirPath);
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("create_directory", arguments)
            );
            
            // 检查结�?
            if (result.content() != null && !result.content().isEmpty()) {
                String resultText = extractTextContent(result.content());
                log.info("创建目录结果: {}", resultText);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            log.error("创建目录失败，路�? {}", dirPath, e);
            throw new RuntimeException("创建目录失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取文件信息
     */
    public Map<String, Object> getFileInfo(String filePath, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of("path", filePath);
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("get_file_info", arguments)
            );
            
            // 提取内容
            if (result.content() != null && !result.content().isEmpty()) {
                String content = extractTextContent(result.content());
                // 简单解析JSON内容
                return parseSimpleJson(content);
            }
            
            return Collections.emptyMap();
            
        } catch (Exception e) {
            log.error("获取文件信息失败，路�? {}", filePath, e);
            throw new RuntimeException("获取文件信息失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 移动/重命名文件或目录
     */
    public boolean moveFile(String sourcePath, String destinationPath, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of(
                "source", sourcePath,
                "destination", destinationPath
            );
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("move_file", arguments)
            );
            
            // 检查结�?
            if (result.content() != null && !result.content().isEmpty()) {
                String resultText = extractTextContent(result.content());
                log.info("移动文件结果: {}", resultText);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            log.error("移动文件失败，源路径: {}, 目标路径: {}", sourcePath, destinationPath, e);
            throw new RuntimeException("移动文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 搜索文件
     */
    public List<String> searchFiles(String dirPath, String pattern, String allowedDirectory) {
        try {
            McpSyncClient client = getOrCreateFileSystemClient(allowedDirectory);
            
            Map<String, Object> arguments = Map.of(
                "path", dirPath,
                "pattern", pattern
            );
            McpSchema.CallToolResult result = client.callTool(
                new McpSchema.CallToolRequest("search_files", arguments)
            );
            
            // 提取内容
            if (result.content() != null && !result.content().isEmpty()) {
                String content = extractTextContent(result.content());
                // 按行分割并返回列�?
                return Arrays.asList(content.split("\n"));
            }
            
            return Collections.emptyList();
            
        } catch (Exception e) {
            log.error("搜索文件失败，目�? {}, 模式: {}", dirPath, pattern, e);
            throw new RuntimeException("搜索文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 关闭指定目录的客户端
     */
    public void closeClient(String allowedDirectory) {
        McpSyncClient client = fsClients.remove(allowedDirectory);
        if (client != null) {
            try {
                client.close();
                log.info("已关闭文件系统MCP客户端，目录: {}", allowedDirectory);
            } catch (Exception e) {
                log.warn("关闭文件系统MCP客户端失败，目录: {}", allowedDirectory, e);
            }
        }
    }
    
    /**
     * 关闭所有客户端
     */
    public void closeAllClients() {
        for (Map.Entry<String, McpSyncClient> entry : fsClients.entrySet()) {
            String dir = entry.getKey();
            McpSyncClient client = entry.getValue();
            try {
                client.close();
                log.info("已关闭文件系统MCP客户端，目录: {}", dir);
            } catch (Exception e) {
                log.warn("关闭文件系统MCP客户端失败，目录: {}", dir, e);
            }
        }
        fsClients.clear();
    }
    
    /**
     * 从MCP结果中提取文本内�?     */
    private String extractTextContent(List<McpSchema.Content> contentList) {
        StringBuilder sb = new StringBuilder();
        for (McpSchema.Content content : contentList) {
            if (content instanceof McpSchema.TextContent) {
                sb.append(((McpSchema.TextContent) content).text());
            }
        }
        return sb.toString();
    }
    
    /**
     * 简单解析JSON内容
     * 这是一个简化的实现，实际项目中应该使用完整的JSON解析�?     */
    private Map<String, Object> parseSimpleJson(String json) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 简单的键值对解析
            String[] pairs = json.replaceAll("[{}\"]", "").split(",");
            for (String pair : pairs) {
                String[] keyValue = pair.split(":");
                if (keyValue.length == 2) {
                    String key = keyValue[0].trim();
                    String value = keyValue[1].trim();
                    result.put(key, value);
                }
            }
        } catch (Exception e) {
            log.warn("解析JSON失败: {}", json, e);
        }
        return result;
    }
}
